﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Configuration;
using System.Timers;
using AppModule.InterProcessComm;
using AppModule.NamedPipes;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using Sinacor.Coletor.WindowsService.Host;

namespace Sinacor.Coletor.WindowsService
{    

    public partial class Coletor : ServiceBase
    {
        Timer timer = new Timer();
        ServiceStatus serviceStatus = new ServiceStatus();
        public Coletor()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            //while (!Debugger.IsAttached)
            //{
            //    System.Threading.Thread.Sleep(1000);
            //}

            serviceStatus.Started = DateTime.Now;
            serviceStatus.ActualPackage = 0;
            serviceStatus.PackageCount = 0;
            serviceStatus.TotalPackage = 0;
            serviceStatus.IdBroker = ConfigurationSettings.AppSettings["ID_BROKER"].ToString();
            serviceStatus.IdMember = Int32.Parse(ConfigurationSettings.AppSettings["ID_MEMBER"].ToString());
            serviceStatus.Inteval = Int32.Parse(ConfigurationSettings.AppSettings["TIME"].ToString());

            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

            timer.Interval = Int32.Parse(ConfigurationSettings.AppSettings["TIME"].ToString()) * 1000;

            timer.Enabled = true;
           
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            timer.Enabled = false;
            try
            {
                RegisterStatus("Verificando sinais para envio.");
                List<HostRequest> listaRequest = new Mensagem().LerMensagem();
                List<HostRequest> listaEnvio = new List<HostRequest>();
                List<HostRequest> listaRetorno = null;
                serviceStatus.TotalPackage = (int)(listaRequest.Count() / 100) + (listaRequest.Count() % 100 == 0 ? 0 : 1);
                serviceStatus.ActualPackage = 0;
                RegisterStatus("Preparando pacotes para envio.");
                for (int i = 0; i < listaRequest.Count; i++)
                {
                    listaEnvio.Add(listaRequest[i]);
                    if ((i + 1) % 100 == 0 || i == listaRequest.Count - 1)
                    {
                        serviceStatus.ActualPackage++;
                        RegisterStatus("Enviando pacote.");
                        HostClient client = new HostClient("WSHttpBinding_IHost");
                        IHost proxy = client.ChannelFactory.CreateChannel();
                        using (proxy as IDisposable)
                        {
                            listaRetorno = proxy.Message(long.Parse(ConfigurationSettings.AppSettings["ID_MEMBER"].ToString()), listaEnvio);
                        }
                        serviceStatus.PackageCount++;
                        RegisterStatus("Registrando envio de pacote.");

                        if (!new Mensagem().GravarMensagem(listaRetorno))
                        {
                            HostRequest falha = listaRetorno.Find(delegate(HostRequest p) { return p.Status == Status.Manutencao; });
                            RegisterStatus("Erro: " + DateTime.Now.ToString() + " - Falha no envio do ultimo pacote.");
                            RegisterStatus("Erro: " + DateTime.Now.ToString() + " - Sinal Enviado: " + falha.DescricaoSinal);
                            RegisterStatus("Erro: " + DateTime.Now.ToString() + " - Mensagem de Erro: " + falha.MensagemErro);
                            break;
                        }
                        listaEnvio.Clear();
                    }
                }
            }
            catch(Exception ex)
            {
                RegisterStatus("Erro: " + DateTime.Now.ToString() + " - " + ex.Message);
                EventLog log = new EventLog();
                log.Source = "Sinacor.Coletor";
                log.WriteEntry(ex.Message, EventLogEntryType.Error, 10, 0);
            }
            finally
            {
                timer.Enabled = true;
                serviceStatus.ActualPackage = 0;
                serviceStatus.TotalPackage = 0;
                RegisterStatus("Aguardando tempo de leitura.");
            }
        }

        private void RegisterStatus(string message)
        {
            serviceStatus.ActualStatus = message;
            IInterProcessConnection clientConnection = null;
            try
            {
                clientConnection = new ClientPipeConnection("ColetorPipe", ".");
                clientConnection.Connect();
                clientConnection.Write(SerializeObject(serviceStatus));
                clientConnection.Read();
                clientConnection.Close();
            }
            catch (Exception ex)
            {
                
            }
            finally
            {
                clientConnection.Dispose();                
            }
        }

        protected override void OnStop()
        {
            timer.Enabled = false;
        }

        public string SerializeObject(Object pObject)
        {
            try
            {
                String XmlizedString = null;
                MemoryStream memoryStream = new MemoryStream();
                XmlSerializer xs = new XmlSerializer(pObject.GetType());
                XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
                xs.Serialize(xmlTextWriter, pObject);
                memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
                XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
                return XmlizedString;
                //return memoryStream.ToArray();
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e);
                return null;
            }
        }

        public Object DeserializeObject(String pXmlizedString, Type type)
        {
            XmlSerializer xs = new XmlSerializer(type);
            MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            return xs.Deserialize(memoryStream);
        }

        private String UTF8ByteArrayToString(Byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

        private Byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        }        
    }

    public class ServiceStatus
    {
        public DateTime Started { get; set; }
        public int PackageCount { get; set; }
        public int ActualPackage { get; set; }
        public int TotalPackage { get; set; }
        public int Inteval { get; set; }
        public string IdBroker { get; set; }
        public int IdMember { get; set; }
        public string ActualStatus { get; set; }
    }
}
